////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//  Filename:    MisterMoneyGuts.cpp                                          //
//  Developer:   George Chapman                                               //
//  Create date: 06/02/2005                                                   //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//  Description: This is the class implementation for the slot gut for the    //
//               Australian Slot machine called Mister Money.                 //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////
//        Copyright (c) 2005 - Realtime Gaming.  All rights reserved.         //
////////////////////////////////////////////////////////////////////////////////

#include "MisterMoneyGuts.h"

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::MisterMoneyGuts()   
///
/// This is the default constructor for the class.
////////////////////////////////////////////////////////////////////////////
MisterMoneyGuts::MisterMoneyGuts() 
{
	m_numPicks = 0;
	m_multipliers = 0;
	m_freeGames = 0;
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::~MisterMoneyGuts()   
///
/// This is the destructor for the class.
////////////////////////////////////////////////////////////////////////////
MisterMoneyGuts::~MisterMoneyGuts() 
{
}
    
////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::classifyStops()   
///
/// @param   stops      The array of stop positions for the line.
/// @param   bet        The value of the line bet.
/// @param   line       The index of the line.
///
/// @return	 uint8      A payout from the SpinResult enumeration as a uint8.    
///
/// This helper method is used to calculate the payout on a line.
////////////////////////////////////////////////////////////////////////////
void
MisterMoneyGuts::classifyStops(SpinLine* spinline, uint8* stops,uint8 bet, uint8 line, uint8& rtnresult, uint8& multiplier)
{
    SpinResult result					  = EVT_LOSER; // spin result :)
  	uint8      testIcon					  = BLANK;     // Icon at current position
	uint8      iconThatIsNotWhiteDiamond  = BLANK;     // Holder for an Icon that is NOT White Diamond
    bool8      hasWhiteDiamond	          = false;     // Indicates if White Lion is part of the evaluation
	uint8	   consecutiveWhiteDiamonds   = 0;

    // By default everything pays at a x1 multiplier
    multiplier = 1;

	//Now, go through the rest, until the streak is over
	for ( uint8 i = 0; (i < getReelCount()); i++ )
    {
		testIcon = getIcon(getGameModeId(), i, stops[i])->iconid;

        // Check to see if it is White Diamond (we bump the count and continue looking)
        if ( testIcon == WHITE_DIAMOND )
        {
            hasWhiteDiamond = true;

			if ( iconThatIsNotWhiteDiamond == BLANK )
			{
				consecutiveWhiteDiamonds++;
			}
        }
        else
        {
            // If we haven't found our first non WhiteDiamond, store it off.
            if ( iconThatIsNotWhiteDiamond == BLANK )
            {
                iconThatIsNotWhiteDiamond = testIcon;
            }
            // If we have found our fist non White Diamond icon, and this icon was not White Diamond
            // and it is not the same as the first non White Diamond icon, then our evaluation stops.
            else if ( iconThatIsNotWhiteDiamond != testIcon )
            {
                break;
            }
        }
    }

    switch ( iconThatIsNotWhiteDiamond )
    {
		case TYCOON:
			if ( i == 5 )
			{
                result = EVT_FIVE_TYCOON;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_TYCOON;
			}
			else if (i == 3)
            {
                result = EVT_THREE_TYCOON;
			}
			else if ( i == 2 )
			{
				result = EVT_TWO_TYCOON;
			}
			break;
 
		case WOMAN:
			if ( i == 5 )
			{
                result = EVT_FIVE_WOMAN;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_WOMAN;
			}
			else if (i == 3)
            {
                result = EVT_THREE_WOMAN;
			}
			else if ( i == 2 )
			{
				result = EVT_TWO_WOMAN;
			}
			break;

        case MANSION:
			if ( i == 5 )
			{
                result = EVT_FIVE_MANSION;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_MANSION;
			}
			else if (i == 3)
            {
                result = EVT_THREE_MANSION;
			}
			else if ( i == 2 )
			{
				result = EVT_TWO_MANSION;
			}
			break;

        case JET:
			if ( i == 5 )
			{
                result = EVT_FIVE_JET;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_JET;
			}
			else if (i == 3)
            {
                result = EVT_THREE_JET;
			}
            break;		
		
        case CAR:
			if ( i == 5 )
			{
                result = EVT_FIVE_CAR;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_CAR;
			}
			else if (i == 3)
            {
                result = EVT_THREE_CAR;
			}
			break;

        case MONEY_BAG:
			if ( i == 5 )
			{
                result = EVT_FIVE_MONEY_BAG;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_MONEY_BAG;
			}
			else if (i == 3)
            {
                result = EVT_THREE_MONEY_BAG;
			}
            break;

        case RING:
			if ( i == 5 )
			{
                result = EVT_FIVE_RING;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_RING;
			}
			else if (i == 3)
            {
                result = EVT_THREE_RING;
			}
            break;

        case WATCH:
			if ( i == 5 )
			{
                result = EVT_FIVE_WATCH;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_WATCH;
			}
			else if (i == 3)
            {
                result = EVT_THREE_WATCH;
			}
            break;

        case BRACELET:
			if ( i == 5 )
			{
                result = EVT_FIVE_BRACELET;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_BRACELET;
			}
			else if (i == 3)
            {
                result = EVT_THREE_BRACELET;
			}
            break;

        case NOTES:
			if ( i == 5 )
			{
                result = EVT_FIVE_NOTES;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_NOTES;
			}
			else if (i == 3)
            {
                result = EVT_THREE_NOTES;
			}
            break;

        case RED_DIAMOND:
            break;

		case BLANK:
			ASSERT( consecutiveWhiteDiamonds == 5 );
			break;

        default:
            // Unknown icon type
            ASSERT(false);
            break;
    }

	if ( consecutiveWhiteDiamonds > 0 )
	{
		SpinResult whiteDiamondResult = EVT_LOSER;
		
		switch ( consecutiveWhiteDiamonds )
		{
			case 1:
				whiteDiamondResult = EVT_ONE_WHITE_DIAMOND;
				break;

			case 2:
				whiteDiamondResult = EVT_TWO_WHITE_DIAMOND;
				break;

			case 3:
				whiteDiamondResult = EVT_THREE_WHITE_DIAMOND;
				break;

			case 4:
				whiteDiamondResult = EVT_FOUR_WHITE_DIAMOND;
				break;

			case 5:
				whiteDiamondResult = EVT_FIVE_WHITE_DIAMOND;
				break;

			default:
				ASSERT(false);
				break;
		}

		if ( getPayout(whiteDiamondResult)->payoutAmount >= getPayout(result)->payoutAmount*MULTIPLIER_WHITE_DIAMOND_2X )
		{
			result = whiteDiamondResult;
		}
	}

	// If we found a White Diamond during evaluation,
	// and we had a winning event that was not a White Diamond
	// winning event, then we had a White Diamond  substitution.  
	// Add the note.
	if ( result != EVT_LOSER                 && 
		 result != EVT_ONE_WHITE_DIAMOND     &&		 
		 result != EVT_TWO_WHITE_DIAMOND     &&
		 result != EVT_THREE_WHITE_DIAMOND   &&
		 result != EVT_FOUR_WHITE_DIAMOND    &&
		 result != EVT_FIVE_WHITE_DIAMOND    &&
		 hasWhiteDiamond ) 
	{
		multiplier *= MULTIPLIER_WHITE_DIAMOND_2X;
		spinline->addNote(NOTE_WHITE_DIAMOND_SUBSTITUTION_2X);
	}

    rtnresult = (uint8) result;
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::classifyScatters()   
///
/// @param   spin       Pointer to the spin with stop data.
///
/// This is an override of the framework method.  
/// It determines if the current spin merits free spins or scatter payments.
////////////////////////////////////////////////////////////////////////////
void 
MisterMoneyGuts::classifyScatters(SlotSpin *spin)
{
	uint8 numRedDiamondsLeftToRight					= 0;
	uint8 numRedDiamondsRightToLeft					= 0;
	bool8 hasWhiteDiamondLeftToRight				= false;
	bool8 hasWhiteDiamondRightToLeft				= false;
    int32 redDiamondsLeftToRightScatterPositions    = 0;
	int32 redDiamondsRightToLeftScatterPositions    = 0;
    //Lets us track IF there's a right-to-left red diamond streak running
    int32 lastRightToLeftRedDiamondReel             = -1;
    bool8 reelHadRedDiamond                         = false;
	uint8 stop							= 0;
	uint8 whichItem						= BLANK;
    uint8 position						= 0;

	// If the current game mode is normal, then
    // check to see if the player won the progressive.
	if (getGameModeId() == MODE_NORMAL ) 
	{
		if ( getRandomProgressiveJackpotResult(spin->getSpinLineCount()) || 
			m_bForceRandomJackpot == true )
        {
			// then add a jackpot scatter to the spin.
			spin->addScatter( 0,
				getPayout( EVT_RANDOM_PROGRESSIVE_WINNER )->payoutAmount, 1,
				true, EVT_RANDOM_PROGRESSIVE_WINNER, 0 );
        }
    }

    // Next, check all the icons at each reel/row position.
    // We are looking for lairs.
  	for (int reel = 0; reel<5; reel++)
	{
        reelHadRedDiamond = false;

    	for (int row = 0; row < 3; row++)
		{
			// Left to Right evaluation
            position = (row*5)+reel;

			stop = relativeWheelPosition(getGameModeId(), reel, spin->getStops()[reel], row);
			whichItem = getIcon(getGameModeId(), reel, stop)->iconid;
			
			if ( whichItem == WHITE_DIAMOND || whichItem == RED_DIAMOND )
			{
                reelHadRedDiamond = true;

				//left to right evaluation
				if ( ( numRedDiamondsLeftToRight ) == reel )
				{
					if ( whichItem == WHITE_DIAMOND )
					{
						hasWhiteDiamondLeftToRight = true;
					}

				    numRedDiamondsLeftToRight++;
				    redDiamondsLeftToRightScatterPositions += 1<<position;
				}
                
                // Right to Left evaluation
                // If we've not had a previous streak running, or this reel continues an existing streak
                // This lets us keep our eyes open for a right-to-left near miss.
                if ( -1 == lastRightToLeftRedDiamondReel
                    || ( numRedDiamondsRightToLeft > 0 && lastRightToLeftRedDiamondReel + 1 == reel ) )
                {
                    // Then this is the last reel to have r-to-l
                    lastRightToLeftRedDiamondReel = reel;

					if ( whichItem == WHITE_DIAMOND )
					{
						hasWhiteDiamondRightToLeft = true;
					}

				    numRedDiamondsRightToLeft++;
				    redDiamondsRightToLeftScatterPositions += 1<<position;
                }
            }
		} // row

        if (! reelHadRedDiamond && (reel < 4) && (lastRightToLeftRedDiamondReel != -1))
        {
            // We were running a r-to-l streak, but now we're not.
            lastRightToLeftRedDiamondReel = -1;
            numRedDiamondsRightToLeft = 0;
			redDiamondsRightToLeftScatterPositions = 0;
        }
	} // reel

    // If we found any red diamond icons, we might
    // have a scatter winner.  If there is only
    // one castle, then this will be a scatter miss.
    // We still send a scatter record so the client
    // can highlight the position and/or play 
    // an anticipation sound on the reel.
	if ( numRedDiamondsLeftToRight > 0 || numRedDiamondsRightToLeft > 0 )
    {
        SpinResult leftToRightPayouttypeid = EVT_SCATTER_NEAR_MISS;
        SpinResult rightToLeftPayouttypeid = EVT_SCATTER_NEAR_MISS;
		SpinResult payouttypeid			   = EVT_SCATTER_NEAR_MISS;
		int32	   leftToRightMultiplier   = 1;
		int32	   rightToLeftMultiplier   = 1;
		int32	   multiplier		       = 1;
		bool8	   hasWhiteDiamond		   = false;
		int32	   scatterPositions		   = 0;
		int32	   numRedDiamonds		   = 0;

	    switch ( numRedDiamondsLeftToRight )
	    {

		   case 2:
			    leftToRightPayouttypeid = EVT_TWO_RED_DIAMOND;
				break;

	       case 3: 
                leftToRightPayouttypeid = EVT_THREE_RED_DIAMOND;
                break;

	       case 4: 
                leftToRightPayouttypeid = EVT_FOUR_RED_DIAMOND;
                break;

           case 5: 
                leftToRightPayouttypeid = EVT_FIVE_RED_DIAMOND;
                break;
	    };


        if ( 4 == lastRightToLeftRedDiamondReel )
        {
            // We made it all the way to the last reel with a running
            // streak of red diamonds.  Set the Payout appropriately.
            switch ( numRedDiamondsRightToLeft )
            {
                
            case 2:
                rightToLeftPayouttypeid = EVT_TWO_RED_DIAMOND;
                break;
                
            case 3: 
                rightToLeftPayouttypeid = EVT_THREE_RED_DIAMOND;
                break;
                
            case 4: 
                rightToLeftPayouttypeid = EVT_FOUR_RED_DIAMOND;
                break;
                
            case 5: 
                rightToLeftPayouttypeid = EVT_FIVE_RED_DIAMOND;
                break;
            };
        }

		// If a white diamond figured into it left to right, then 
		// that payout is multiplied by 2
		if ( hasWhiteDiamondLeftToRight ) 
		{
			leftToRightMultiplier = MULTIPLIER_WHITE_DIAMOND_2X;
		}

		// If a white diamond figured into it right to left, then 
		// that payout is multiplied by 2
		if ( hasWhiteDiamondRightToLeft )
		{
			rightToLeftMultiplier = MULTIPLIER_WHITE_DIAMOND_2X;
		}

		// Choose the highest payout: Left to Right or Right to Left
        int32 leftToRightPayout = getPayout(leftToRightPayouttypeid)->payoutAmount*leftToRightMultiplier;
        int32 rightToLeftPayout = getPayout(rightToLeftPayouttypeid)->payoutAmount*rightToLeftMultiplier;
		if ( leftToRightPayout > rightToLeftPayout 
            || ( leftToRightPayout == rightToLeftPayout 
                && numRedDiamondsLeftToRight >= numRedDiamondsRightToLeft ) )
		{
			payouttypeid	 = leftToRightPayouttypeid;
			multiplier		 = leftToRightMultiplier;
			hasWhiteDiamond  = hasWhiteDiamondLeftToRight;
			scatterPositions = redDiamondsLeftToRightScatterPositions;
			numRedDiamonds   = numRedDiamondsLeftToRight;
		}
		else
		{
			payouttypeid	 = rightToLeftPayouttypeid;
			multiplier       = rightToLeftMultiplier;
			hasWhiteDiamond  = hasWhiteDiamondRightToLeft;
			scatterPositions = redDiamondsRightToLeftScatterPositions;
			numRedDiamonds   = numRedDiamondsRightToLeft;
		}

		// During free spin feature there are multipliers applied.
		if ( getGameModeId() == MODE_FREE_SPIN )
		{
			multiplier *= getFeatureGameMultiplier();
		}
        
		int32 nPayout = getPayout(payouttypeid)->payoutAmount * ( spin->getSpinLineCount());

        increaseTotalWin(nPayout*multiplier);

        // Let's create a scatter record for the
        // Castles.
	    SlotScatter* pScatter = spin->addScatter( scatterPositions, 
                                                  nPayout*getBetPerLine(),
                                                  multiplier,
                                                  false,
                                                  payouttypeid,
                                                  0 );

        // In free spin mode, write a note about the variable multiplier.
		if ( getGameModeId() == MODE_FREE_SPIN )
		{
			pScatter->addNote(NOTE_FREE_SPIN_MULTIPLIER);
		}

		// If a White diamond contributed toward the scatter
		if ( hasWhiteDiamond )
		{
			pScatter->addNote(NOTE_WHITE_DIAMOND_SUBSTITUTION_2X);
		}

		// Let's check for a feature trigger.
		if ( payouttypeid != EVT_SCATTER_NEAR_MISS && payouttypeid != EVT_TWO_RED_DIAMOND )
		{
			if ( getGameModeId() == MODE_FREE_SPIN )
			{
				int32 nFreeSpins = 0;

				switch( payouttypeid )
				{
					case EVT_THREE_RED_DIAMOND:
						nFreeSpins = FREE_SPINS_THREE_RED_DIAMOND;
						break;

					case EVT_FOUR_RED_DIAMOND:
						nFreeSpins = FREE_SPINS_FOUR_RED_DIAMOND;
						break;

					case EVT_FIVE_RED_DIAMOND:
						nFreeSpins = FREE_SPINS_FIVE_RED_DIAMOND;
						break;

					default:
						ASSERT(false);
						break;
				}

				pScatter = spin->addScatter( scatterPositions,
											 0,
											 1,
											 false,
											 EVT_FREE_GAME_FEATURE,
											 nFreeSpins );

				incrementFreeSpins(nFreeSpins);

			}
			else
			{
				pScatter = spin->addScatter( scatterPositions,
											 0,
											 1,
											 false,
											 EVT_FREE_GAME_PICK,
											 INITIAL_FREE_GAME_AWARD );

				initializePickFeatureGame(numRedDiamonds);
			}
		}
		else
		{
				pScatter = spin->addScatter( scatterPositions,
											 0,
											 1,
											 false,
											 EVT_FEATURE_NEAR_MISS,
											 0 );
		}
	
		// special case where both scatters need to be paid
		if ( leftToRightPayouttypeid == EVT_TWO_RED_DIAMOND &&
			 rightToLeftPayouttypeid == EVT_TWO_RED_DIAMOND )
		{
			// Choose the unpaid (lowest) payout: Left to Right or Right to Left
			if ( getPayout(leftToRightPayouttypeid)->payoutAmount*leftToRightMultiplier <
				 getPayout(rightToLeftPayouttypeid)->payoutAmount*rightToLeftMultiplier )
			{
				payouttypeid	 = leftToRightPayouttypeid;
				multiplier		 = leftToRightMultiplier;
				hasWhiteDiamond  = hasWhiteDiamondLeftToRight;
				scatterPositions = redDiamondsLeftToRightScatterPositions;
				numRedDiamonds   = numRedDiamondsLeftToRight;
			}
			else
			{
				payouttypeid	 = rightToLeftPayouttypeid;
				multiplier       = rightToLeftMultiplier;
				hasWhiteDiamond  = hasWhiteDiamondRightToLeft;
				scatterPositions = redDiamondsRightToLeftScatterPositions;
				numRedDiamonds   = numRedDiamondsRightToLeft;
			}

			// During free spin feature there are multipliers applied.
			if ( getGameModeId() == MODE_FREE_SPIN )
			{
				multiplier *= getFeatureGameMultiplier();
			}
        
			int32 nPayout = getPayout(payouttypeid)->payoutAmount * ( spin->getSpinLineCount());

			increaseTotalWin(nPayout*multiplier);

			// Let's create a scatter record for the
			// Castles.
			SlotScatter* pScatter = spin->addScatter( scatterPositions, 
													  nPayout*getBetPerLine(),
													  multiplier,
													  false,
													  payouttypeid,
													  0 );

			// In free spin mode, write a note about the variable multiplier.
			if ( getGameModeId() == MODE_FREE_SPIN )
			{
				pScatter->addNote(NOTE_FREE_SPIN_MULTIPLIER);
			}

			// If a White diamond contributed toward the scatter
			if ( hasWhiteDiamond )
			{
				pScatter->addNote(NOTE_WHITE_DIAMOND_SUBSTITUTION_2X);
			}
		}
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::isValidGuts()   
///
/// @return	 bool8      True if gut is valid.    
///
/// This helper method is used to the current gut ID is valid.
////////////////////////////////////////////////////////////////////////////
bool8 
MisterMoneyGuts::isValidGuts()
{
    return (getGutsId() >= 1000 && getGutsId() < 1099);
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::setFeatureGameMultiplier(int32 nFeatureGameMultiplier) 
///
/// @param   nFeatureGameMultiplier  The multiplier awarded for the feature.
///
/// This is a mutator to set the multiplier applied to the feature game.
////////////////////////////////////////////////////////////////////////////
void 
MisterMoneyGuts::setFeatureGameMultiplier(int32 nFeatureGameMultiplier)
{
    m_subGame->update(SGDIDX_FEATURE_MULTIPLIER,nFeatureGameMultiplier);
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::getFeatureGameMultiplier() const 
///
/// @return  int32   The multiplier awarded for the feature.
///
/// This is an accessor mutator method to get the multiplier applied to the feature game.
////////////////////////////////////////////////////////////////////////////
int32 
MisterMoneyGuts::getFeatureGameMultiplier() const
{
    return m_subGame->getData(SGDIDX_FEATURE_MULTIPLIER);
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::setFeatureGameNumPicks(int32 nNumPicks) 
///
/// @param   nNumPicks  The number of money bags the player will get to pick.
///
/// This is a mutator to set the number of money bags the player will get to pick.
////////////////////////////////////////////////////////////////////////////
void		  
MisterMoneyGuts::setFeatureGameNumPicks(int32 nNumPicks)
{
	ASSERT( nNumPicks <= MAX_MONEY_BAG_PICKS );

    m_subGame->update(SGDIDX_NUM_MONEY_BAGS,nNumPicks);
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::getFeatureGameNumPicks() const 
///
/// @return  int32   The number of money bags the player will get to pick.
///
/// This is an accessor mutator method to get the number of money bags the player will get to pick.
////////////////////////////////////////////////////////////////////////////
int32		  
MisterMoneyGuts::getFeatureGameNumPicks() const
{
	return m_subGame->getData(SGDIDX_NUM_MONEY_BAGS);
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::getFeatureNumBagsSelected() const 
///
/// @return  int32   The number of money bags that have been selected..
///
/// This is an accessor mutator method to get the number of money bags that have been selected.
////////////////////////////////////////////////////////////////////////////
int32
MisterMoneyGuts::getFeatureNumBagsSelected() const
{
	int32 nCount = 0;

	for ( int32 i = 0; i < MAX_POSITIONS; i++ )
	{
		int32 nMask = 1<<i;

		if ( getFeatureGamePositionMask() & nMask )
		{
			nCount++;
		}
	}

	return nCount;
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::setFeatureGamePickPosition(int32 nIndex, int32 nPickPosition) 
///
/// @param   nIndex  The index of the money bag.
/// @param   nPickPosition  The position of the selected money bag.
///
/// This is a mutator to set the position of the selected money bag.
////////////////////////////////////////////////////////////////////////////
void		  
MisterMoneyGuts::setFeatureGamePickPosition(int32 nIndex, int32 nPickPosition)
{
	if ( nPickPosition >= 0 && nPickPosition < MAX_POSITIONS )
	{
		if ( nIndex >= getFeatureGameNumPicks() )
		{
			nPickPosition = 0;
		}

		m_subGame->update((SGDIDX_PICK_POSITION_1+(2*nIndex)),nPickPosition);
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::getFeatureGamePickPosition(int32 nIndex) const
///
/// @param   nIndex  The index of the money bag.
///
/// @return  int32   The position of the selected money bag.
///
/// This is an accessor mutator method to get the position of the selected money bag.
////////////////////////////////////////////////////////////////////////////
int32		  
MisterMoneyGuts::getFeatureGamePickPosition(int32 nIndex) const	
{
	int32 nReturn = -1;

	if ( nIndex < getFeatureGameNumPicks() )
	{
		nReturn = m_subGame->getData(SGDIDX_PICK_POSITION_1+(2*nIndex));
	}

	return nReturn;
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::setFeatureGamePickType(int32 nIndex, int32 nPickType)
///
/// @param   nIndex  The index of the money bag.
/// @param   nPickType  The type of win awarded for the money bag pick.
///
/// This is a mutator to set the type of win awarded for the money bag pick.
////////////////////////////////////////////////////////////////////////////
void		  
MisterMoneyGuts::setFeatureGamePickType(int32 nIndex, int32 nPickType)
{
	if ( ( nIndex >= 0 && nIndex < MAX_POSITIONS ) &&
		 ( nPickType == WIN_TYPE_NONE               ||
		   nPickType == WIN_TYPE_THREE_FREE_GAMES   ||
		   nPickType == WIN_TYPE_MULTIPLIER_INCREASE 
		 ) 
	   )
	{
		if ( nIndex >= getFeatureGameNumPicks() )
		{
			nPickType = WIN_TYPE_NONE;
		}

		m_subGame->update((SGDIDX_PICK_TYPE_1+(2*nIndex)),nPickType);
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::getFeatureGamePickType(int32 nIndex) const 
///
/// @param   nIndex  The index of the money bag.
///
/// @return  int32   The type of win awarded for the money bag pick.
///
/// This is an accessor mutator method to get the type of win awarded for the money bag pick.
////////////////////////////////////////////////////////////////////////////
int32		  
MisterMoneyGuts::getFeatureGamePickType(int32 nIndex) const
{
	int32 nReturn = -1;

	if ( nIndex < getFeatureGameNumPicks() )
	{
		nReturn = m_subGame->getData(SGDIDX_PICK_TYPE_1+(2*nIndex));
	}

	return nReturn;
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::setFeatureGamePositionMask(int32 nMask)
///
/// @param   nMask  The mask for all positions (selected and not selected).
///
/// This is a mutator to set the mask for all positions (selected and not selected).
////////////////////////////////////////////////////////////////////////////
void		  
MisterMoneyGuts::setFeatureGamePositionMask(int32 nMask)
{
	if ( nMask >= 0 && nMask < ( 1 << ( MAX_POSITIONS + 1 ) ) )
	{
	    m_subGame->update(SGDIDX_FEATURE_BAG_SELECTED_MASK,nMask);
	}
	else
	{
		ASSERT(false);
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::getFeatureGamePositionMask() const 
///
/// @return  int32   The mask for all positions (selected and not selected).
///
/// This is an accessor mutator method to get mask for all positions (selected and not selected).
////////////////////////////////////////////////////////////////////////////
int32		  
MisterMoneyGuts::getFeatureGamePositionMask() const
{
	return m_subGame->getData(SGDIDX_FEATURE_BAG_SELECTED_MASK);
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::setFeatureGamePositionSelected( int32 nPosition, bool8 bSelected )
///
/// @param   nPosition  The position to set as selected or not selected.
///
/// @return  bSelected  Selected or not selected state of the position.
///
/// This is a mutator to set the position to selected or not selected.
////////////////////////////////////////////////////////////////////////////
void          
MisterMoneyGuts::setFeatureGamePositionSelected( int32 nPosition, bool8 bSelected )
{
	if ( nPosition >= 0 && nPosition < MAX_POSITIONS)
	{
		int32 nMask = 1<<nPosition;

		if ( bSelected )
		{
			nMask = ( nMask | getFeatureGamePositionMask() );
		}
		else
		{
			nMask = ( ~nMask & getFeatureGamePositionMask() );
		}

		setFeatureGamePositionMask(nMask);
	}
	else
	{
		ASSERT(false);
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::getFeatureGamePositionSelected( int32 nPosition ) const 
///
/// @param   nPosition  The position to set as selected or not selected.
///
/// @return  bool8      Selected or not selected state of the position.
///
/// This is an accessor mutator method to get the position as selected or not selected.
////////////////////////////////////////////////////////////////////////////
bool8		  
MisterMoneyGuts::getFeatureGamePositionSelected( int32 nPosition ) const
{
	bool8 bReturn = false;

	if ( nPosition >= 0 && nPosition < MAX_POSITIONS)
	{
		int32 nMask = 1<<nPosition;
		bReturn = (bool8) ( getFeatureGamePositionMask() & nMask );
	}
	else
	{
		ASSERT(false);
	}

	return bReturn;
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::incrementFeatureTriggerCount() 
///
/// This is a mutator to increment the current feature game mutliplier.
////////////////////////////////////////////////////////////////////////////
void 
MisterMoneyGuts::incrementFeatureGameMultiplier()
{
    setFeatureGameMultiplier(getFeatureGameMultiplier()+1);
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::initializePickFeatureGame() 
///
/// This is a helper method to initialize the pick feature game.
////////////////////////////////////////////////////////////////////////////
void
MisterMoneyGuts::initializePickFeatureGame(int32 numRedDiamonds)
{
	setGameCanComplete(false);
	setBonusGameState(BONUS_GAME_PICK_MONEY_BAGS);
	setFeatureGameMultiplier(INITIAL_FREE_GAME_MULTIPLIER);
	setFeatureGamePositionMask(0);
	setFeatureGameNumPicks( numRedDiamonds );

	for ( int32 i = 0; i < MAX_MONEY_BAG_PICKS; i++ )
	{
		setFeatureGamePickPosition( i, 0 );
		setFeatureGamePickType( i, WIN_TYPE_NONE );
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::processClientData()
///
/// @param   bonusGameType      The current type of bonus game.
/// @param   bonusDataCount     The number of integers passed from the client.
/// @param   bonusData			An array of integers passed from the client.
/// 
/// This is an override of the framework method.
/// 
////////////////////////////////////////////////////////////////////////////
bool8
MisterMoneyGuts::processClientData(uint8 bonusGameType, int32 bonusDataCount, int32 *bonusData)
{
	// Start by assuming that we do not need to reply to this message
	bool8 bReply = false;

	if ( getBonusGameState() == BONUS_GAME_PICK_MONEY_BAGS )
	{
		if ( bonusGameType == BONUS_GAME_PICK_MONEY_BAGS )
		{
			if ( bonusDataCount == 1 )
			{
				int32 nPosition = *bonusData;

				if ( nPosition >= 0 && nPosition < MAX_POSITIONS )
				{
					if ( getFeatureGamePositionSelected( nPosition ) )
					{
						// Position already selected.  Log it.
					}
					else
					{
						// The state will change, so a reply is required
						bReply = true;

						if ( getFeatureNumBagsSelected() < getFeatureGameNumPicks() )
						{
							int32 nWinType = getRandomValueFromProbabilityTable(PT_BONUS_GAME_PICK_VALUE);

							if(m_bDebugSpinsMode)
							{
								if(g_nDebugPickPrizes[getFeatureNumBagsSelected()] != WIN_TYPE_NONE)
								{
									nWinType = g_nDebugPickPrizes[getFeatureNumBagsSelected()];
								}
							}

							if ( nWinType == WIN_TYPE_THREE_FREE_GAMES )
							{
								incrementFreeSpins(FEATURE_FREE_GAMES_INCREASE);
							}
							else if ( nWinType == WIN_TYPE_MULTIPLIER_INCREASE )
							{
								incrementFeatureGameMultiplier();
							}
							else
							{
								// This should not happen.
								ASSERT(false);
							}

							setFeatureGamePickPosition( getFeatureNumBagsSelected(), nPosition );
							setFeatureGamePickType( getFeatureNumBagsSelected(), nWinType );
							setFeatureGamePositionSelected( nPosition, true );

							if ( getFeatureNumBagsSelected() == getFeatureGameNumPicks() )
							{
								SlotSpin* pSpin = getSlotSpin();
								m_feature->setLevel( 1 );

								// Index 0 in the intial free game award
								incrementFreeSpins(INITIAL_FREE_GAME_AWARD);

								//FB Case 14568 - We don't need this one.  The details below are sufficient.
								//pSpin->addBonusGame( 0, 0, 0, 0, 0, INITIAL_FREE_GAME_AWARD, 0 );	

								for ( int i = 0; i < getFeatureNumBagsSelected(); i++ )
								{
									int32 nFreeSpins = 0;
									int32 nAdditionalMultiplier = 0;

									if ( getFeatureGamePickType( i ) == WIN_TYPE_THREE_FREE_GAMES )
									{
										nFreeSpins = FEATURE_FREE_GAMES_INCREASE;
									}
									else if ( getFeatureGamePickType( i ) == WIN_TYPE_MULTIPLIER_INCREASE )
									{
										nAdditionalMultiplier = FEATURE_MULTIPLIER_INCREASE;
									}

									// Add bonus games
									pSpin->addBonusGame( 0, i, 0, nAdditionalMultiplier, 0, nFreeSpins, 0 );	

									// Add feature game data
									m_feature->update( SGDIDX_PICK_POSITION_1+(i*2), getFeatureGamePickPosition(i), true ); 
									m_feature->update( SGDIDX_PICK_TYPE_1+(i*2), getFeatureGamePickType(i), true );
								}

								m_numPicks += getFeatureGameNumPicks();
								m_multipliers += ( getFeatureGameMultiplier() - INITIAL_FREE_GAME_MULTIPLIER);
								m_freeGames += ( getFreeSpins() - INITIAL_FREE_GAME_AWARD );

								setGameModeId(MODE_FREE_SPIN);
								setBonusGameState(BONUS_GAME_NONE);
								setGameCanComplete(true);

								if(m_bDebugSpinsMode)
								{
									//reset debug data
									g_nDebugPick = -1;
									for(int x=0; x<MAX_MONEY_BAG_PICKS; x++)
										g_nDebugPickPrizes[x] = WIN_TYPE_NONE;
								}
							}
						}
						else
						{
							// Trying to pick a bag when there are no more picks left.
						}
					}
				}
				else
				{
					// Invalid position.  Log it.
				}
			}
			else
			{
				// Too many data items.  Log it.
			}
		}
		else
		{
			// Invalid bonus game type from client.  Log it.
		}
	}
	else
	{
		//  Invalid state to receive this message.  Log it.
	} 

	return bReply;
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::getGameModeMultiplierAndNoteId( uint8& nGameModeMultiplier, uint8& nNoteId )   
///
/// @param	 nGameModeMultiplier    Returns the new multiplier based on the game mode.
/// @param   nNoteId                Returns the note Id associated with the game mode.
///
/// This helper method is get the game mode note and multiplier.
////////////////////////////////////////////////////////////////////////////
void 
MisterMoneyGuts::getGameModeMultiplierAndNoteId( uint8& nGameModeMultiplier, uint8& nNoteId )
{
	// During free spin feature there are multipliers applied.
    if ( getGameModeId() == MODE_FREE_SPIN )
    {
        nNoteId = NOTE_FREE_SPIN_MULTIPLIER;
        nGameModeMultiplier = getFeatureGameMultiplier();
    }
    else
    {
        SlotGuts::getGameModeMultiplierAndNoteId( nGameModeMultiplier, nNoteId );
    }

}
 
////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::hasSavedGames()   
///
/// This helper method is a framework override that indicates this machine can have saved games.
////////////////////////////////////////////////////////////////////////////
bool8
MisterMoneyGuts::hasSavedGames()
{
	return true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//
//	Debugging code
//
////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////
/// @fn 	 MisterMoneyGuts::preSpinClassifyResults()   
///
/// @param   spin       Pointer to the spin with stop data.
///
/// This method is overridden when running in debug spins mode to alter the reel stops.
////////////////////////////////////////////////////////////////////////////
void MisterMoneyGuts::preSpinClassifyResults( SlotSpin* spin )
{
	SlotGuts::preSpinClassifyResults(spin);
	return;
}


////////////////////////////////////////////////////////////////////////////
/// Debug spins functionality, can control what prizes are revealed
/// behind the panels
////////////////////////////////////////////////////////////////////////////
void MisterMoneyGuts::initDebugFunctionMap()
{
	SlotGuts::initDebugFunctionMap();

	addDebugStopFunction( EVT_DEBUG_FUNCTION_PICK_SPINS, 
		new DebugStopFunc<MisterMoneyGuts>(this, &MisterMoneyGuts::DebugFeature_PickSpins) );

	addDebugStopFunction( EVT_DEBUG_FUNCTION_PICK_MULT, 
		new DebugStopFunc<MisterMoneyGuts>(this, &MisterMoneyGuts::DebugFeature_PickMult) );
}

int MisterMoneyGuts::g_nDebugPick = -1;
int MisterMoneyGuts::g_nDebugPickPrizes[5] = { WIN_TYPE_NONE };

void MisterMoneyGuts::DebugFeature_PickSpins( SlotSpin *spin )
{
	g_nDebugPick++;

	if(g_nDebugPick >= 0 && g_nDebugPick < MAX_MONEY_BAG_PICKS)
		g_nDebugPickPrizes[g_nDebugPick] = WIN_TYPE_THREE_FREE_GAMES;
	else
		g_nDebugPick = -1;
}

void MisterMoneyGuts::DebugFeature_PickMult( SlotSpin *spin )
{
	g_nDebugPick++;

	if(g_nDebugPick >= 0 && g_nDebugPick < MAX_MONEY_BAG_PICKS)
		g_nDebugPickPrizes[g_nDebugPick] = WIN_TYPE_MULTIPLIER_INCREASE;
	else
		g_nDebugPick = -1;
}